#include "system.h" 

unsigned short xpos, ypos;
unsigned short *videoram;
unsigned short color;

unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count){
	int i;
	unsigned char * o_dest = dest;

	for (i = 0; i < count; i++)
		dest[i] = src[i];
	return o_dest;
}

unsigned char *memset(unsigned char *dest, unsigned char val, int count){
	int i;
	unsigned char * o_dest = dest;

	for (i = 0; i < count; i++)
		dest[i] = val;
	return o_dest;
}

unsigned short *memsetw(unsigned short *dest, unsigned short val, int count){
	int i;
	unsigned short * o_dest = dest;

	for (i = 0; i < count; i++)
		dest[i] = val;
	return o_dest;
}

int strlen(const char *str){
	int i;

	for (i = 0; *str != '\0'; i++, str++);
	return i;
}

unsigned char inportb (unsigned short _port){
	unsigned char rv;
	__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
	return rv;
}

void outportb (unsigned short _port, unsigned char _data){
	__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

/*************
 * Screen related functions
 * */

void move_csr(void)
{
	unsigned temp;

	temp = ypos * 80 + xpos;

	outportb(0x3D4, 14);
	outportb(0x3D5, temp >> 8);
	outportb(0x3D4, 15);
	outportb(0x3D5, temp);
}

void putc(const char c){
	/* backspace */
	if(c == 0x08)
	{
		if(xpos != 0) xpos--;
	}
	else if (c == '\n') {
		xpos = 0;
		ypos++;
	} 
	else if (c == '\t') {
		xpos = (xpos + 8) & ~(8 - 1);
		if (xpos >= 80){
			xpos -= 80;
			ypos++;
		}
	} 
	else if (c == '\r') {
		xpos = 0;
	}
	else if (c >= ' ')
	{
		videoram[ypos*80 + xpos] = (color << 8) | c;
		xpos++;
	}

	if (xpos >= 80) {
		xpos = 0;
		ypos++;
	}

	if (ypos >= 25)
		scroll_screen();

	move_csr();
}

void puts(const char *str){
	int i;
	for (i = 0; i < strlen(str); i++){ 
		putc(str[i]);
	}
}

void cls(){
	int i;

	xpos = ypos = 0;
	for (i = 0; i < 25; i++)
		memsetw(videoram, ' ', 80);
}

void init_video(){
	videoram = (unsigned short *) 0xb8000;
	cls();
	color = 0x07;
}

void scroll_screen(){
	int i;
	unsigned char *video = (unsigned char *)videoram;

	for (i = 1; i < 25; i++)
		memcpy(&video[(i-1)*160], &video[i*160], 160);

	ypos = 24;
	memsetw(&videoram[ypos*80], ' ', 80);
}

void settextcolor(unsigned char forecolor, unsigned char backcolor){
	color = (backcolor << 4) | (forecolor & 0x0F);	
}

